﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Globalization;
using System.Xml.Linq;
using System.Web.Hosting;
using System.IO;

namespace PinCity.Localization
{
    /// <summary>
    /// Helper class that returns localized strings given their keys.
    /// </summary>
    public static class LocalizationManager
    {
        private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(typeof(LocalizationManager));
        /// <summary>
        /// Contains current culture settings if not specified otherwise
        /// </summary>
        private static CultureInfo defaultCulture;
        /// <summary>
        /// Library of all available localizations
        /// </summary>
        private static IDictionary<CultureInfo, Localization> library = new Dictionary<CultureInfo, Localization>();

        /// <summary>
        /// Gets or sets used default culture name. If no culture settings found in LocalizationSettings.xml no changes occur.
        /// </summary>
        public static string DefaultCultureName
        {
            get
            {
                return LocalizationManager.defaultCulture.Name;
            }
            private set
            {
                LocalizationManager.SetDefaultCulture(value);
            }

        }
        /// <summary>
        /// Gets or sets used default culture. If no culture settings found in LocalizationSettings.xml no changes occur.
        /// </summary>
        public static CultureInfo DefaultCultureInfo
        {
            get
            {
                return LocalizationManager.defaultCulture;
            }
            set
            {
                LocalizationManager.SetDefaultCulture(value.Name);
            }
        }


        /// <summary>
        /// Changes used culture without changing default culture.
        /// </summary>
        /// <param name="cultureName">Name of culture that is used</param>
        private static void SetDefaultCulture(string cultureName)
        {
            XDocument CultureFile = XDocument.Load(HostingEnvironment.MapPath("~/App_LocalResources/Localization/LocalizationSettings.xml"));       //Opens Localization settings.xml
            IEnumerable<XElement> cultures = CultureFile.Root.Descendants("set");       //Creates collection of all available culture settings.
            XElement element = cultures.FirstOrDefault(e => e.Attribute("cultureName").Value.Equals(cultureName, StringComparison.OrdinalIgnoreCase));      //Gets needed set from LocalizationSettings.xml, containing filepath and name of culture.
            if (element != null)    //If such set was found...
            {
                LocalizationManager.defaultCulture = CultureInfo.GetCultureInfo(cultureName);       //Sets current culture to <cultureName>
            }
            else throw new Exception("Web.config does not contain default culture info.");
        }

        /// <summary>
        /// Initialization :\
        /// </summary>
        public static void Initialize()
        {
            XDocument localizationSettingsXml = XDocument.Load(HostingEnvironment.MapPath("~/App_LocalResources/Localization/LocalizationSettings.xml"));       //Opens Localization settings.xml
            IEnumerable<XElement> cultures = localizationSettingsXml.Root.Descendants("set");       //Creates collection of all available culture settings.
            foreach (XElement dict in cultures)     //Filling our localization library
            {
                string dictFilePath = HostingEnvironment.MapPath(dict.Attribute("fileName").Value);     //contains absolute filepath to localization XMl file
                if (File.Exists(dictFilePath))      //if such file exists...
                {
                    FileStream dictFileStream = new FileStream(dictFilePath, FileMode.Open);        //Open filestream for Localization constructor
                    LocalizationManager.library.Add(CultureInfo.GetCultureInfo(dict.Attribute("cultureName").Value), new Localization(dictFileStream, CultureInfo.GetCultureInfo(dict.Attribute("cultureName").Value)));        //Add new localization object to our library
                    dictFileStream.Close();     //Close filestream, so the file can be accessed elsewhere
                }
                else LocalizationManager.logger.Error("Localization XML file for " + dict.Attribute("cultureName").Value + "does not exist");
            }
            LocalizationManager.SetDefaultCulture(ConfigurationManager.AppSettings["defaultCulture"]);      //Set default culture

        }

        /// <summary>
        /// Gets localized string, given its key. Culture is assumed to be default.
        /// </summary>
        /// <param name="key">Key of returning string. Must be present in corresponding localization file.</param>
        /// <returns>Returns localized string. If no key found in corresponding localization XML file returns key itself.</returns>
        public static string GetString(string key)
        {
            string result = key.ToUpper();
            result = LocalizationManager.GetString(key, LocalizationManager.DefaultCultureName);        //retrieves specific localized string from default dictionary
            return result;
        }

        /// <summary>
        /// Gets localized string, given its key for the choosen culture.
        /// </summary>
        /// <param name="key">Key of returning string. Must be present in corresponding localization file.</param>
        /// <param name="cultureName">Name of the culture, whose localized string is returned.</param>
        /// <returns>Returns localized string. If no key found in corresponding localization XML file returns key itself.</returns>
        public static string GetString(string key, string cultureName)
        {
            string result = key.ToUpper();
            if (LocalizationManager.library.Keys.Contains(CultureInfo.GetCultureInfo(cultureName)))
            {
                result = LocalizationManager.library[CultureInfo.GetCultureInfo(cultureName)].GetString(key);   //retrieves specific localized string from specific dictionary
            }
            else if(LocalizationManager.defaultCulture != null) result = LocalizationManager.GetString(key);      //return default localized string
            else LocalizationManager.logger.Error("Localization for " + cultureName + " was not implemented.");     //return key and log error message
            return result;
        }

        /// <summary>
        /// Gets localized string, given its key for the choosen culture.
        /// </summary>
        /// <param name="key">Key of returning string. Must be present in corresponding localization file.</param>
        /// <param name="cultureName">Name of the culture, whose localized string is returned.</param>
        /// <returns>Returns localized string. If no key found in corresponding localization XML file returns key itself.</returns>
        public static string GetString(string key, CultureInfo culture)
        {
            string result = key.ToUpper();
            if (LocalizationManager.library.Keys.Contains(culture))
            {
                result = LocalizationManager.library[culture].GetString(key);       //retrieves specific localized string from specific dictionary
            }
            else if (LocalizationManager.defaultCulture != null) result = LocalizationManager.GetString(key);      //return default localized string
            else LocalizationManager.logger.Error("Localization for " + culture.Name + " was not implemented.");     //return key and log error message
            return result;
        }

    }
}
